/* @internal */
名域 ts {
    /**
     * Partial interface of the System thats needed to support the caching of 目录 structure
     */
    导出 接口 目录结构主机_ {
        文件存在(路径: 文字): 真假;
        读文件(路径: 文字, 编码?: 文字): 文字 | 未定;

        目录存在?(路径: 文字): 真假;
        获取目录?(路径: 文字): 文字[];
        读目录?(路径: 文字, 扩展名组?: 只读数组_<文字>, 深度?: 数字): 文字[];

        创建目录?(路径: 文字): 无值;
        写文件?(路径: 文字, 数据: 文字, 写字节序或标志?: 真假): 无值;
    }

    接口 文件和目录存在_ {
        文件存在: 真假;
        目录存在: 真假;
    }

    导出 接口 缓存目录文件主机_ 扩展 目录结构主机_ {
        使用区分大小写文件名: 真假;

        获取目录(路径: 文字): 文字[];
        读目录(路径: 文字, 扩展名组?: 只读数组_<文字>, 深度?: 数字): 文字[];

        /** Returns the queried 结果 for the 文件 exists and 目录 exists if at all it was done */
        添加或删除文件或目录(文件或目录: 文字, 文件或目录路径: 路径_): 文件和目录存在_ | 未定;
        添加或删除文件(文件名: 文字, 文件路径: 路径_, 事件种类: 文件监控事件种类_): 无值;
        清除缓存(): 无值;
    }

    接口 多文件系统条目_ {
        只读 文件组: 文字[];
        只读 目录组: 文字[];
    }

    导出 函数 创建缓存目录结构主机(主机: 目录结构主机_, 当前目录: 文字, 使用区分大小写文件名: 真假): 缓存目录文件主机_ | 未定 {
        如果 (!主机.获取目录 || !主机.读目录) {
            返回 未定;
        }

        常量 缓存读取目录结果 = 创建词典<多文件系统条目_>();
        常量 获取规范文件名称 = 创建获取规范文件名称(使用区分大小写文件名);
        返回 {
            使用区分大小写文件名: 使用区分大小写文件名,
            文件存在: 文件存在,
            读文件: (路径, 编码) => 主机.读文件(路径, 编码),
            目录存在: 主机.目录存在 && 目录存在,
            获取目录: 获取目录,
            读目录: 读目录,
            创建目录: 主机.创建目录 && 创建目录,
            写文件: 主机.写文件 && 写文件,
            添加或删除文件或目录: 添加或删除文件或目录,
            添加或删除文件: 添加或删除文件,
            清除缓存: 清除缓存
        };

        函数 转为路径(文件名: 文字) {
            返回 ts.转为路径(文件名, 当前目录, 获取规范文件名称);
        }

        函数 获取缓存文件系统条目(根目录路径: 路径_): 多文件系统条目_ | 未定 {
            返回 缓存读取目录结果.获取(根目录路径);
        }

        函数 获取基本目录的缓存文件系统条目(路径: 路径_): 多文件系统条目_ | 未定 {
            返回 获取缓存文件系统条目(获取目录路径(路径));
        }

        函数 获取文件名的基名称(文件名: 文字) {
            返回 获取基文件名称(正规化路径(文件名))!;
        }

        函数 创建缓存文件系统条目(根目录: 文字, 根目录路径: 路径_) {
            常量 结果从主机: 多文件系统条目_ = {
                文件组: 词典(主机.读目录!(根目录, /*extensions*/ 未定), 获取文件名的基名称) || [],
                目录组: 主机.获取目录!(根目录) || []
            };

            缓存读取目录结果.设置(根目录路径, 结果从主机);
            返回 结果从主机;
        }

        /**
         * If the readDirectory 结果 was already cached, it returns that
         * Otherwise gets 结果 from 主机 and caches it.
         * The 主机 request is done under try catch 块 to avoid caching incorrect 结果
         */
        函数 尝试读目录(根目录: 文字, 根目录路径: 路径_): 多文件系统条目_ | 未定 {
            常量 缓存结果 = 获取缓存文件系统条目(根目录路径);
            如果 (缓存结果) {
                返回 缓存结果;
            }

            尝试 {
                返回 创建缓存文件系统条目(根目录, 根目录路径);
            }
            捕获 (_e) {
                // If there is exception to read directories, dont cache the 结果 and direct the calls to 主机
                调试_.断言(!缓存读取目录结果.具有(根目录路径));
                返回 未定;
            }
        }

        函数 文件名称相等(name1: 文字, name2: 文字) {
            返回 获取规范文件名称(name1) === 获取规范文件名称(name2);
        }

        函数 具有条目(条目组: 只读数组_<文字>, 名称: 文字) {
            返回 某些(条目组, 文件 => 文件名称相等(文件, 名称));
        }

        函数 更新文件系统条目(条目组: 文字[], 基名称: 文字, 是有效: 真假) {
            如果 (具有条目(条目组, 基名称)) {
                如果 (!是有效) {
                    返回 过滤多维(条目组, 条目 => !文件名称相等(条目, 基名称));
                }
            }
            否则 如果 (是有效) {
                返回 条目组.压入(基名称);
            }
        }

        函数 写文件(文件名: 文字, 数据: 文字, 写主机或标志?: 真假): 无值 {
            常量 路径 = 转为路径(文件名);
            常量 结果 = 获取基本目录的缓存文件系统条目(路径);
            如果 (结果) {
                文件系统条目更新文件组(结果, 获取文件名的基名称(文件名), /*fileExists*/ 为真);
            }
            返回 主机.写文件!(文件名, 数据, 写主机或标志);
        }

        函数 文件存在(文件名: 文字): 真假 {
            常量 路径 = 转为路径(文件名);
            常量 结果 = 获取基本目录的缓存文件系统条目(路径);
            返回 结果 && 具有条目(结果.文件组, 获取文件名的基名称(文件名)) ||
                主机.文件存在(文件名);
        }

        函数 目录存在(目录路径: 文字): 真假 {
            常量 路径 = 转为路径(目录路径);
            返回 缓存读取目录结果.具有(路径) || 主机.目录存在!(目录路径);
        }

        函数 创建目录(目录路径: 文字) {
            常量 路径 = 转为路径(目录路径);
            常量 结果 = 获取基本目录的缓存文件系统条目(路径);
            常量 基文件名 = 获取文件名的基名称(目录路径);
            如果 (结果) {
                更新文件系统条目(结果.目录组, 基文件名, /*isValid*/ 为真);
            }
            主机.创建目录!(目录路径);
        }

        函数 获取目录(根目录: 文字): 文字[] {
            常量 根目录路径 = 转为路径(根目录);
            常量 结果 = 尝试读目录(根目录, 根目录路径);
            如果 (结果) {
                返回 结果.目录组.分切();
            }
            返回 主机.获取目录!(根目录);
        }

        函数 读目录(根目录: 文字, 扩展名组?: 只读数组_<文字>, 深度?: 数字): 文字[] {
            常量 根目录路径 = 转为路径(根目录);
            常量 结果 = 尝试读目录(根目录, 根目录路径)!;
            如果 (结果) {
                返回 匹配文件(根目录, 扩展名组!,   当前目录, 深度, 获取文件系统条目);
            }
            返回 主机.读目录!(根目录, 扩展名组, 深度);

            函数 获取文件系统条目(目录: 文字) {
                常量 路径 = 转为路径(目录);
                如果 (路径 === 根目录路径) {
                    返回 结果;
                }
                返回 尝试读目录(目录, 路径) || 空文件系统条目;
            }
        }

        函数 添加或删除文件或目录(文件或目录: 文字, 文件或目录路径: 路径_) {
            常量 现有结果 = 获取缓存文件系统条目(文件或目录路径);
            如果 (现有结果) {
                // Just clear the cache for now
                // For now just clear the cache, since this could mean that multiple level entries might need to be re-evaluated
                清除缓存();
                返回 未定;
            }

            常量 父结果 = 获取基本目录的缓存文件系统条目(文件或目录路径);
            如果 (!父结果) {
                返回 未定;
            }

            // This was earlier a 文件 (hence not in cached 目录 contents)
            // or we never cached the 目录 containing it

            如果 (!主机.目录存在) {
                // Since 主机 doesnt support 目录 exists, clear the cache as otherwise it might not be same
                清除缓存();
                返回 未定;
            }

            常量 基名称 = 获取文件名的基名称(文件或目录);
            常量 fs查询结果: 文件和目录存在_ = {
                文件存在: 主机.文件存在(文件或目录路径),
                目录存在: 主机.目录存在(文件或目录路径)
            };
            如果 (fs查询结果.目录存在 || 具有条目(父结果.目录组, 基名称)) {
                // Folder added or removed, clear the cache instead of updating the folder and its structure
                清除缓存();
            }
            否则 {
                // No need to update the 目录 structure, just files
                文件系统条目更新文件组(父结果, 基名称, fs查询结果.文件存在);
            }
            返回 fs查询结果;

        }

        函数 添加或删除文件(文件名: 文字, 文件路径: 路径_, 事件种类: 文件监控事件种类_) {
            如果 (事件种类 === 文件监控事件种类_.改变的_) {
                返回;
            }

            常量 父结果 = 获取基本目录的缓存文件系统条目(文件路径);
            如果 (父结果) {
                文件系统条目更新文件组(父结果, 获取文件名的基名称(文件名), 事件种类 === 文件监控事件种类_.创建的_);
            }
        }

        函数 文件系统条目更新文件组(父结果: 多文件系统条目_, 基名称: 文字, 文件存在: 真假) {
            更新文件系统条目(父结果.文件组, 基名称, 文件存在);
        }

        函数 清除缓存() {
            缓存读取目录结果.清除();
        }
    }

    导出 枚举 配置文件程序加载级别_ {
        无_,
        /** Update the 文件 名称 列表 from the disk */
        部分的_,
        /** Reload completely by re-reading contents of config 文件 from disk and updating program */
        全部_
    }

    /**
     * Updates the existing 失踪的 文件 watches with the new set of 失踪的 files after new program is created
     */
    导出 函数 更新失踪文件路径监控(
        程序: 程序_,
        失踪文件监控者: 词典_<文件监控_>,
        创建失踪文件监控: (失踪文件路径: 路径_) => 文件监控_,
    ) {
        常量 失踪文件路径组 = 程序.获取失踪文件路径();
        常量 新失踪文件路径词典 = 数组转为集合(失踪文件路径组);
        // Update the 失踪的 文件 paths watcher
        多维词典(
            失踪文件监控者,
            新失踪文件路径词典,
            {
                // Watch the 失踪的 files
                创建新值: 创建失踪文件监控,
                // Files that are no longer 失踪的 (e.g. because they are no longer required)
                // should no longer be watched.
                正在删除值: 关闭文件监控
            }
        );
    }

    导出 接口 通配符目录监控者_ {
        监控者: 文件监控_;
        标志: 监控目录标志_;
    }

    /**
     * Updates the existing wild card 目录 watches with the new set of wild card directories from the config 文件
     * after new program is created because the config 文件 was reloaded or program was created 首个 time from the config 文件
     * Note that there is no need to call this function when the program is updated with additional files without reloading config files,
     * as wildcard directories wont change unless reloading config 文件
     */
    导出 函数 更新监控通配符目录(
        正在监控的通配符: 词典_<通配符目录监控者_>,
        通配符目录: 词典_<监控目录标志_>,
        监控目录: (目录: 文字, 标志: 监控目录标志_) => 文件监控_
    ) {
        多维词典(
            正在监控的通配符,
            通配符目录,
            {
                // Create new watch and recursive info
                创建新值: 创建通配符目录监控者,
                // Close existing watch thats not needed any more
                正在删除值: 关闭文件监控者的,
                // Close existing watch that doesnt match in the 标志
                正在现有值: 更新通配符监控者
            }
        );

        函数 创建通配符目录监控者(目录: 文字, 标志: 监控目录标志_): 通配符目录监控者_ {
            // Create new watch and recursive info
            返回 {
                监控者: 监控目录(目录, 标志),
                标志
            };
        }

        函数 更新通配符监控者(现有监控者: 通配符目录监控者_, 标志: 监控目录标志_, 目录: 文字) {
            // Watcher needs to be updated if the recursive 标志 dont match
            如果 (现有监控者.标志 === 标志) {
                返回;
            }

            现有监控者.监控者.close();
            正在监控的通配符.设置(目录, 创建通配符目录监控者(目录, 标志));
        }
    }

    导出 函数 是已发出程序文件(程序: 程序_ | 未定, 文件: 文字) {
        如果 (!程序) {
            返回 为假;
        }

        返回 程序.是输出的文件(文件);
    }

    导出 枚举 监控日志级别_ {
        无_,
        仅触发器_,
        详细_
    }

    导出 接口 监控文件主机_ {
        监控文件(路径: 文字, 回调: 文件监控回调_, 轮询间隔?: 数字): 文件监控_;
    }
    导出 接口 监控目录主机_ {
        监控目录(路径: 文字, 回调: 目录监控回调_, 递归?: 真假): 文件监控_;
    }
    导出 类型 监控文件_<X, Y> = (主机: 监控文件主机_, 文件: 文字, 回调: 文件监控回调_, 轮询间隔: 轮询间隔_, 详细信息1?: X, 详细信息2?: Y) => 文件监控_;
    导出 类型 文件路径监控者回调_ = (文件名: 文字, 事件种类: 文件监控事件种类_, 文件路径: 路径_) => 无值;
    导出 类型 监控文件路径_<X, Y> = (主机: 监控文件主机_, 文件: 文字, 回调: 文件路径监控者回调_, 轮询间隔: 轮询间隔_, 路径: 路径_, 详细信息1?: X, 详细信息2?: Y) => 文件监控_;
    导出 类型 监控目录_<X, Y> = (主机: 监控目录主机_, 目录: 文字, 回调: 目录监控回调_, 标志: 监控目录标志_, 详细信息1?: X, 详细信息2?: Y) => 文件监控_;

    导出 接口 监控工厂_<X, Y> {
        监控文件: 监控文件_<X, Y>;
        监控文件路径: 监控文件路径_<X, Y>;
        监控目录: 监控目录_<X, Y>;
    }

    导出 函数 获取监控工厂<X = 未定, Y = 未定>(监控日志级别: 监控日志级别_, 日志: (s: 文字) => 无值, 获取详细监控信息?: 获取详细监控信息_<X, Y>): 监控工厂_<X, Y> {
        返回 获取监控工厂包括(监控日志级别, 日志, 获取详细监控信息, 监控文件, 监控目录);
    }

    函数 获取监控工厂包括<X = 未定, Y = 未定>(监控日志级别: 监控日志级别_, 日志: (s: 文字) => 无值, 获取详细监控信息: 获取详细监控信息_<X, Y> | 未定,
        监控文件: (主机: 监控文件主机_, 文件: 文字, 回调: 文件监控回调_, 监控优先级: 轮询间隔_) => 文件监控_,
        监控目录: (主机: 监控目录主机_, 目录: 文字, 回调: 目录监控回调_, 标志: 监控目录标志_) => 文件监控_): 监控工厂_<X, Y> {
        常量 创建文件监控者: 创建文件监控者_<监控文件主机_, 轮询间隔_, 文件监控事件种类_, 未定, X, Y> = 获取创建文件监控者(监控日志级别, 监控文件);
        常量 创建文件路径监控者: 创建文件监控者_<监控文件主机_, 轮询间隔_, 文件监控事件种类_, 路径_, X, Y> = 监控日志级别 === 监控日志级别_.无_ ? 监控文件路径 : 创建文件监控者;
        常量 创建目录监控者: 创建文件监控者_<监控目录主机_, 监控目录标志_, 未定, 未定, X, Y> = 获取创建文件监控者(监控日志级别, 监控目录);
        返回 {
            监控文件: (主机, 文件, 回调, 轮询间隔, 详细信息1, 详细信息2) =>
                创建文件监控者(主机, 文件, 回调, 轮询间隔, /*通过*/ 未定, 详细信息1, 详细信息2, 监控文件, 日志, '文件监控_', 获取详细监控信息),
            监控文件路径: (主机, 文件, 回调, 轮询间隔, 路径, 详细信息1, 详细信息2) =>
                创建文件路径监控者(主机, 文件, 回调, 轮询间隔, 路径, 详细信息1, 详细信息2, 监控文件, 日志, '文件监控_', 获取详细监控信息),
            监控目录: (主机, 目录, 回调, 标志, 详细信息1, 详细信息2) =>
                创建目录监控者(主机, 目录, 回调, 标志, /*通过*/ 未定, 详细信息1, 详细信息2, 监控目录, 日志, '目录监控_', 获取详细监控信息)
        };

        函数 监控文件路径(主机: 监控文件主机_, 文件: 文字, 回调: 文件路径监控者回调_, 轮询间隔: 轮询间隔_, 路径: 路径_): 文件监控_ {
            返回 监控文件(主机, 文件, (文件名, 事件种类) => 回调(文件名, 事件种类, 路径), 轮询间隔);
        }
    }

    函数 监控文件(主机: 监控文件主机_, 文件: 文字, 回调: 文件监控回调_, 轮询间隔: 轮询间隔_): 文件监控_ {
        返回 主机.监控文件(文件, 回调, 轮询间隔);
    }

    函数 监控目录(主机: 监控目录主机_, 目录: 文字, 回调: 目录监控回调_, 标志: 监控目录标志_): 文件监控_ {
        返回 主机.监控目录(目录, 回调, (标志 & 监控目录标志_.递归_) !== 0);
    }

    类型 监控回调_<T, U> = (文件名: 文字, 回调可选的?: T, 通过?: U) => 无值;
    类型 添加监控_<H, T, U, V> = (主机: H, 文件: 文字, cb: 监控回调_<U, V>, 标志: T, 通过?: V, 详细信息1?: 未定, 详细信息2?: 未定) => 文件监控_;
    导出 类型 获取详细监控信息_<X, Y> = (详细信息1: X, 详细信息2: Y) => 文字;

    类型 创建文件监控者_<H, T, U, V, X, Y> = (主机: H, 文件: 文字, cb: 监控回调_<U, V>, 标志: T, 通过: V | 未定, 详细信息1: X | 未定, 详细信息2: Y | 未定, 添加监控: 添加监控_<H, T, U, V>, log: (s: 文字) => 无值, watchCaption: 文字, 获取详细监控信息: 获取详细监控信息_<X, Y> | 未定) => 文件监控_;
    函数 获取创建文件监控者<H, T, U, V, X, Y>(监控日志级别: 监控日志级别_, 添加监控: 添加监控_<H, T, U, V>): 创建文件监控者_<H, T, U, V, X, Y> {
        假如 (监控日志级别) {
            若是 监控日志级别_.无_:
                返回 添加监控;
            若是 监控日志级别_.仅触发器_:
                返回 创建文件监控者包括触发日志;
            若是 监控日志级别_.详细_:
                返回 创建文件监控者包括日志;
        }
    }

    函数 创建文件监控者包括日志<H, T, U, V, X, Y>(主机: H, 文件: 文字, cb: 监控回调_<U, V>, 标志: T, 通过: V | 未定, 详细信息1: X | 未定, 详细信息2: Y | 未定, 添加监控: 添加监控_<H, T, U, 未定>, 日志: (s: 文字) => 无值, 监控标题: 文字, 获取详细监控信息: 获取详细监控信息_<X, Y> | 未定): 文件监控_ {
        日志(`${监控标题}:: 添加:: ${获取监控信息(文件, 标志, 详细信息1, 详细信息2, 获取详细监控信息)}`);
        常量 监控者 = 创建文件监控者包括触发日志(主机, 文件, cb, 标志, 通过, 详细信息1, 详细信息2, 添加监控, 日志, 监控标题, 获取详细监控信息);
        返回 {
            close: () => {
                日志(`${监控标题}:: 关闭:: ${获取监控信息(文件, 标志, 详细信息1, 详细信息2, 获取详细监控信息)}`);
                监控者.close();
            }
        };
    }

    函数 创建文件监控者包括触发日志<H, T, U, V, X, Y>(主机: H, 文件: 文字, 回调: 监控回调_<U, V>, 标志: T, 通过: V | 未定, 详细信息1: X | 未定, 详细信息2: Y | 未定, 添加监控: 添加监控_<H, T, U, 未定>, 日志: (s: 文字) => 无值, 监控标题: 文字, 获取详细监控信息: 获取详细监控信息_<X, Y> | 未定): 文件监控_ {
        返回 添加监控(主机, 文件, (文件名, 回调可选的) => {
            常量 触发信息 = `${监控标题}:: 触发包括 ${文件名}${回调可选的 !== 未定 ? 回调可选的 : ''}:: ${获取监控信息(文件, 标志, 详细信息1, 详细信息2, 获取详细监控信息)}`;
            日志(触发信息);
            常量 开始 = 时间戳();
            回调(文件名, 回调可选的, 通过);
            常量 结束的 = 时间戳() - 开始;
            日志(`用时:: ${结束的}ms ${触发信息}`);
        }, 标志);
    }

    函数 获取监控信息<T, X, Y>(文件: 文字, 标志: T, 详细信息1: X | 未定, 详细信息2: Y | 未定, 获取详细监控信息: 获取详细监控信息_<X, Y> | 未定) {
        返回 `监控信息: ${文件} ${标志} ${获取详细监控信息 ? 获取详细监控信息(详细信息1!, 详细信息2!) : ''}`;
    }

    导出 函数 关闭文件监控者的<T 扩展 { 监控者: 文件监控_; }>(对象包括监控者: T) {
        对象包括监控者.监控者.close();
    }
}
